#pragma once

#include <iostream>
#include <vector>
#include <algorithm>
#include <thread>
#include <memory>
#include <unordered_map>
#include <thread>
#include <functional>
#include <mutex>
#include <condition_variable>
#include <cstdint>
#include <cassert>
#include <cstring>
#include <sys/epoll.h>

#include "Log.hpp"
#include "Buffer.hpp"
#include "Socket.hpp"
#include "Channel.hpp"
#include "Poller.hpp"
#include "TimerWheel.hpp"
#include "EventLoop.hpp"
#include "Any.hpp"
#include "Connection.hpp"
#include "Acceptor.hpp"
#include "LoopThread.hpp"

class TcpServer
{
    using ConnectedCallback = std::function<void(const ConnectionPtr&)>;
    using ClosedCallback = std::function<void(const ConnectionPtr&)>;
    using MessageCallback = std::function<void(const ConnectionPtr&, Buffer*)>;
    using EventCallback = std::function<void(const ConnectionPtr&)>;
    using SvrClosedCallback = std::function<void()>;
private:
    EventLoop _baseloop;// 主线程对应的loop，对 监听连接 的操作都通过这个完成
    Acceptor _acceptor;// 监听连接。用于监听获取新连接
    LoopThreadPool _threadpool;// 从属线程池。对通信连接的操作和任务处理都在从属线程中进行
    uint64_t _conn_id;// 要分配的下一个用户态连接id
    std::unordered_map<uint64_t, ConnectionPtr> _conns;// 服务器模块管理通信连接
    bool _enable_idle_release;// 非活跃连接释放标志
    uint32_t _timeout;// 非活跃连接标准超时时间

    ConnectedCallback _connected_cb;// （用户态）连接建立成功的回调函数
    ClosedCallback _closed_cb;// 连接关闭的回调函数
    MessageCallback _message_cb;// 有信息到来的回调函数（接收缓冲区中有数据，可直接处理）
    EventCallback _event_cb;// 任意事件产生的回调函数
private:
    /* 移除对连接的管理 */
    // void ReleaseConnectionInThreadLoop(uint64_t conn_id)
    // {
    //     _conns.erase(conn_id);
    // }
    void ReleaseConnectionInThreadLoop(const ConnectionPtr& conn)
    {
        _conns.erase(conn->Id());
    }


    /* 新连接到来的回调函数 */
    void NewConnection(int sockfd)
    {
        // 1. 创建Connection管理新连接
        ConnectionPtr conn(new Connection(_conn_id, _threadpool.NextLoop(), sockfd));
        // 2. 设置回调函数
        conn->SetConnectedCallback(_connected_cb);
        conn->SetClosedCallback(_closed_cb);
        conn->SetMessageCallback(_message_cb);
        conn->SetEventCallback(_event_cb);
        /* 这个地方按道理来说编译就应该报错的，bind了两个值，就相当于是ReleaseConnection函数没有形参了
        而ClosedCallback函数类型是需要一个形参的，类型都不匹配，是会编译报错的，但这里没有编译报错，所以是有个地方类型重了
        */
        // conn->SetSvrClosedCallback(std::bind(&TcpServer::ReleaseConnection, this, _conn_id));
        conn->SetSvrClosedCallback(std::bind(&TcpServer::ReleaseConnection, this, std::placeholders::_1));
        // 3. 启动非活跃连接超时释放功能
        if(_enable_idle_release) conn->EnableIdleRelease(_timeout);
        // 4. 初始化新连接——完成连接完全建立前的准备工作
        conn->ConnectionEstablished();
        // 5. 添加对新连接的管理
        _conns.insert(std::make_pair(_conn_id, conn));
        // 6. 下一个分配的连接id自增
        ++_conn_id;
    }
    

    /* 移除对连接的管理 */
    // void ReleaseConnection(uint64_t conn_id)
    // {
    //     _baseloop.RunTaskInLoopThread(std::bind(&TcpServer::ReleaseConnectionInThreadLoop, this, conn_id));
    // }
    void ReleaseConnection(const ConnectionPtr& conn )
    {
        _baseloop.RunTaskInLoopThread(std::bind(&TcpServer::ReleaseConnectionInThreadLoop, this, conn));
    }
public:
    TcpServer(uint16_t port): 
        _acceptor(&_baseloop, port), _threadpool(&_baseloop), _conn_id(1), _enable_idle_release(false)
    {
        // 1. 设置新连接到来的回调函数
        _acceptor.SetAcceptedCallback(std::bind(&TcpServer::NewConnection, this, std::placeholders::_1));
    }

    /* 设置回调函数 */
    void SetConnectedCallback(const ConnectedCallback& cb)
    {
        _connected_cb = cb;
    }
    void SetClosedCallback(const ClosedCallback& cb)
    {
        _closed_cb = cb;
    }
    void SetMessageCallback(const MessageCallback& cb)
    {
        _message_cb = cb;
    }
    void SetEventCallback(const EventCallback& cb)
    {
        _event_cb = cb;
    }

    /* 设置线程池大小——从属线程个数 */
    void SetLoopThreadCount(size_t count)
    {
        _threadpool.SetThreadCount(count);
    }

    /* 启动非活跃连接超时销毁 */
    void EnableIdelRelease(uint32_t timeout)
    {
        _timeout = timeout;
        _enable_idle_release = true;
    }


    /* 启动服务器 */
    void Start()
    {
        // 1. 创建线程池
        _threadpool.CreateThreads();
        INF_LOG("CREATEING THREADPOOL WITH %ld THREADS SUCCESS", _threadpool.ThreadCount());
        // 2. 启动监听套接字的读事件监控
        _acceptor.Listen();
        // 3. 运行loop
        INF_LOG("SERVER STARTS LISTENING NEW CONNECTION");// 这个应该放在_baseloop.Start()中打印，但为了功能上的解耦，就放在外面了
        _baseloop.Start();
    }
};